#ifndef MEASURE_SIZE_TRACKER_VECTOR_2_H_
#define MEASURE_SIZE_TRACKER_VECTOR_2_H_

#if defined(_MSC_VER)
#pragma once
#endif

#include "fast_trigonometries.h"
#include <boost/math/special_functions/round.hpp>

class vector_2 {
public:
  vector_2(void) : vx(0), vy(0) {}
  vector_2(double vxval, double vyval) : vx(vxval), vy(vyval) {}
  ~vector_2(void) {}

  vector_2(const vector_2& vt)
  {
    if (this != &vt) {
      vx = vt.vx;
      vy = vt.vy;
    }
  }

  vector_2& operator=(const vector_2& vt)
  {
    if (this != &vt) {
      vx = vt.vx;
      vy = vt.vy;
    }

    return *this;
  }

public:
  double length(void) const { return sqrt(vx*vx+vy*vy); }
  double length2(void) const { return vx*vx+vy*vy; }

  int angle(void) const
  {
    return angle_math::normalize(boost::math::iround(angle_math::degree(atan2(vy, vx))));
  }

  vector_2 normalize() const { return *this/length(); }

  vector_2 rotate(int a) const
  { 
    return vector_2(vx*kCos[a]-vy*kSin[a], vx*kSin[a]+vy*kCos[a]);
  }

public:
  bool operator==(const vector_2& vt) const { return vx==vt.vx && vy==vt.vy; }
  bool operator!=(const vector_2& vt) const { return !(*this==vt); }
  friend vector_2 operator-(const vector_2& vt) { return vector_2(-vt.vx, -vt.vy); }
  friend vector_2 operator~(const vector_2& vt) { return vector_2(-vt.vy, vt.vx); }

  friend vector_2 operator+(const vector_2& lvt, const vector_2& rvt)
  { 
    return vector_2(lvt.vx+rvt.vx, lvt.vy+rvt.vy);
  }

  friend vector_2 operator-(const vector_2& lvt, const vector_2& rvt) 
  { 
    return vector_2(lvt.vx-rvt.vx, lvt.vy-rvt.vy); 
  }

  friend vector_2 operator*(const vector_2& lvt, double rsv) 
  { 
    return vector_2(lvt.vx*rsv, lvt.vy*rsv); 
  }

  friend vector_2 operator*(double lsv, const vector_2& rvt) 
  { 
    return rvt*lsv; 
  }

  friend vector_2 operator/(const vector_2& lvt, double rsv) 
  { 
    return vector_2(lvt.vx/rsv, lvt.vy/rsv); 
  }

  friend double operator*(const vector_2& lvt, const vector_2& rvt) 
  { 
    return lvt.vx*rvt.vx+lvt.vy*rvt.vy; 
  }

  friend double operator|(const vector_2& lvt, const vector_2& rvt) 
  { 
    return lvt.vx*rvt.vy-lvt.vy*rvt.vx; 
  }

public:
  vector_2& operator+=(const vector_2& rvt) 
  { 
    vx+=rvt.vx; 
    vy+=rvt.vy; 
    return *this; 
  }

  vector_2& operator-=(const vector_2& rvt) 
  { 
    vx-=rvt.vx; 
    vy-=rvt.vy; 
    return *this; 
  }

  vector_2& operator*=(double rsv) 
  { 
    vx*=rsv; 
    vy*=rsv; 
    return *this; 
  }

  vector_2& operator/=(double rsv) 
  { 
    vx/=rsv; 
    vy/=rsv; 
    return *this; 
  }

public:
  bool left(const vector_2& vt) const { return (vt|*this)>0; }
  bool right(const vector_2& vt) const { return (vt|*this)<0; }
  bool acute(const vector_2& vt) const { return ((*this)*vt)>0; }
  bool obtuse(const vector_2& vt) const { return ((*this)*vt)<0; }

public:
  double vx;
  double vy;
};

#endif // MEASURE_SIZE_TRACKER_VECTOR_2_H_